package com.caishi.lkx.order.pay;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.*;
import com.alipay.api.request.*;
import com.alipay.api.response.*;
import com.alipay.api.AlipayResponse;
import com.caishi.lkx.common.config.DiamondConfig;
import com.caishi.lkx.order.model.OrderModel;
import com.caishi.lkx.user.service.IGroupService;
import com.zzw.common.exception.BizRuntimeException;
import com.caishi.lkx.order.OrderResultCode;
import com.caishi.lkx.order.config.AlipayConfig;
import com.caishi.lkx.order.model.PaymentModel;
import com.caishi.lkx.order.model.PaymentRefundLogModel;
import com.caishi.lkx.order.service.IOrderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.context.annotation.Configuration;

import javax.annotation.Resource;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author by keray
 * date:2019/9/9 11:48
 */
@Configuration(value = "ZFBOnlinePay")
@Slf4j
@ConditionalOnBean(name = "alipayConfig")
public class ZFBPayPlugins implements PayPlugins {

    @Resource
    private IOrderService orderService;
    @Resource
    private IGroupService groupService;

    @Resource
    private DiamondConfig diamondConfig;

    protected final AlipayConfig alipayConfig;

    protected volatile AlipayClient alipayClient = null;

    private static final ConcurrentHashMap<Long, Object> lockMap = new ConcurrentHashMap<>();

    public ZFBPayPlugins(@Qualifier("alipayConfig") AlipayConfig alipayConfig) {
        this.alipayConfig = alipayConfig;
    }

    public enum AlipayType {
        // app支付
        app,
        // h5 支付
        h5,
        // 二维码支付
        qrCode,
        // pc支付
        pc,
        unknown
    }

    @Override
    public boolean open() {
        return true;
    }

    @Override
    public Map<String, Object> sign(PaymentModel paymentModel, Object val, Map<String, Object> otherParam) {
        AlipayResponse response = null;
        try {
            if (val == AlipayType.app) {
                response = _appPay(paymentModel);
            } else if (val == AlipayType.h5) {
                response = _h5Pay(paymentModel);
            } else if (val == AlipayType.qrCode) {
                response = _qrPay(paymentModel);
            } else if (val == AlipayType.pc) {
                response = _pcPay(paymentModel, otherParam);
            } else {
                response = _defaultPay(paymentModel);
            }
            if (response.isSuccess()) {
                Map<String, Object> result = BeanUtil.beanToMap(response);
                try {
                    result.putAll(JSON.parseObject(response.getBody()));
                } catch (Exception ignored) {
                }
                return result;
            } else {
                log.warn("app支付获取创建支付信息失败 data={}", response);
            }
        } catch (AlipayApiException e) {
            log.error("支付宝支付签名异常:", e);
        }
        throw new BizRuntimeException(OrderResultCode.payFail);
    }

    @Override
    public boolean prePayCallBack(PaymentModel paymentModel) {
        AlipayTradeQueryModel queryModel = new AlipayTradeQueryModel();
        queryModel.setOutTradeNo(paymentModel.getOrderSn());
        AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
        request.setBizModel(queryModel);
        OrderModel orderModel = orderService.getById(paymentModel.getOrderId());
        try {
            AlipayTradeQueryResponse response = getClient(orderModel.getGroupId()).execute(request);
            if (response.isSuccess()) {
                return "TRADE_SUCCESS".equals(response.getTradeStatus());
            } else {
                log.error("支付订单查询失败 data={}", response);
            }
        } catch (AlipayApiException e) {
            log.error("支付宝订单查询失败：", e);
        }
        //  查询失败邮件通知处理
        return true;
    }

    @Override
    public boolean refund(PaymentModel paymentModel, PaymentRefundLogModel paymentRefundLogModel) {
        if (fetchRefund(paymentModel, paymentRefundLogModel)) {
            return true;
        }
        log.info("开始支付宝退款 paymentId={},logId={}", paymentModel.getId(), paymentRefundLogModel.getId());
        AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
        AlipayTradeRefundModel model = new AlipayTradeRefundModel();
        request.setBizModel(model);
        model.setOutTradeNo(paymentModel.getOrderSn());
        model.setRefundAmount(paymentRefundLogModel.getRefundAmountBigDecimal().toPlainString());
        OrderModel orderModel = orderService.getById(paymentModel.getOrderId());

        // 设置退款编号，在多次退款中必须唯一
        model.setOutRequestNo(paymentRefundLogModel.getId());
        try {
            AlipayTradeRefundResponse refundResponse = getClient(orderModel.getGroupId()).execute(request);
            if (refundResponse.isSuccess()) {
                return true;
            }
        } catch (AlipayApiException e) {
            e.printStackTrace();
            log.error("支付宝退款失败", e);
        }
        return false;
    }

    private boolean fetchRefund(PaymentModel paymentModel, PaymentRefundLogModel paymentRefundLogModel) {
        AlipayTradeFastpayRefundQueryRequest request = new AlipayTradeFastpayRefundQueryRequest();
        AlipayTradeFastpayRefundQueryModel model = new AlipayTradeFastpayRefundQueryModel();
        request.setBizModel(model);
        model.setOutTradeNo(paymentModel.getOrderSn());
        model.setOutRequestNo(paymentRefundLogModel.getId());

        OrderModel orderModel = orderService.getById(paymentModel.getOrderId());

        try {
            AlipayTradeFastpayRefundQueryResponse response = getClient(orderModel.getGroupId()).execute(request);
            if (response.isSuccess()) {
                return "".equals(response.getRefundStatus()) || "REFUND_SUCCESS".equals(response.getRefundStatus());
            }
        } catch (AlipayApiException e) {
            e.printStackTrace();
            log.error("支付宝退款查询失败", e);
        }
        return false;
    }

    @Override
    public void orderCancel(PaymentModel paymentModel) {
        try {
            AlipayTradeCloseRequest request = new AlipayTradeCloseRequest();
            AlipayTradeCloseModel model = new AlipayTradeCloseModel();
            model.setOutTradeNo(paymentModel.getOrderSn());
            OrderModel orderModel = orderService.getById(paymentModel.getOrderId());
            getClient(orderModel.getGroupId()).execute(request);
        } catch (Exception e) {
            log.error("支付宝订单关闭异常", e);
        }
    }

    private AlipayTradeAppPayResponse _appPay(PaymentModel paymentModel) throws AlipayApiException {
        AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
        AlipayTradeAppPayModel payModel = new AlipayTradeAppPayModel();
        payModel.setOutTradeNo(paymentModel.getOrderSn());
        OrderModel orderModel = orderService.getById(paymentModel.getOrderId());
        //TODO: 支付金额
        //payModel.setTotalAmount("0.01");
        payModel.setTotalAmount(paymentModel.getPaymentAmountDecimal().toPlainString());
        payModel.setSubject(orderService.getOrderOnlinePayTitle(paymentModel.getOrderId()));
        payModel.setTimeoutExpress(StrUtil.format("{}m", diamondConfig.getOrderPayValiditySeconds() / 60));
        request.setNotifyUrl(groupService.getById(orderModel.getGroupId()).getAlipayNotifyUrl());
        payModel.setProductCode("QUICK_MSECURITY_PAY");
        request.setBizModel(payModel);

        return getClient(orderModel.getGroupId()).sdkExecute(request);
    }

    @Deprecated
    private AlipayTradeWapPayResponse _h5Pay(PaymentModel paymentModel) throws AlipayApiException {
        AlipayTradeWapPayRequest request = new AlipayTradeWapPayRequest();
        AlipayTradeWapPayModel payModel = new AlipayTradeWapPayModel();
        OrderModel orderModel = orderService.getById(paymentModel.getOrderId());
        payModel.setOutTradeNo(paymentModel.getOrderSn());
        payModel.setTotalAmount(paymentModel.getPaymentAmountDecimal().toPlainString());
        payModel.setSubject(orderService.getOrderOnlinePayTitle(paymentModel.getOrderId()));
        payModel.setTimeoutExpress(StrUtil.format("{}m", diamondConfig.getOrderPayValiditySeconds() / 60));
        payModel.setProductCode("QUICK_WAP_WAY");
        payModel.setQuitUrl(null);
        request.setNotifyUrl(groupService.getById(orderModel.getGroupId()).getAlipayNotifyUrl());
        request.setBizModel(payModel);
        return getClient(orderModel.getGroupId()).pageExecute(request);
    }

    private AlipayTradePagePayResponse _pcPay(PaymentModel paymentModel, Map<String, Object> otherParam) throws AlipayApiException {
        AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
        AlipayTradePagePayModel payModel = new AlipayTradePagePayModel();

        OrderModel orderModel = orderService.getById(paymentModel.getOrderId());
        var group = groupService.getById(orderModel.getGroupId());
        payModel.setOutTradeNo(paymentModel.getOrderSn());
        payModel.setTotalAmount(paymentModel.getPaymentAmountDecimal().toPlainString());
        payModel.setSubject(orderService.getOrderOnlinePayTitle(paymentModel.getOrderId()));
        payModel.setProductCode("FAST_INSTANT_TRADE_PAY");
        request.setNotifyUrl(group.getAlipayNotifyUrl());
        request.setBizModel(payModel);
        request.setReturnUrl(group.getAlipayReturnUrl());
        return getClient(orderModel.getGroupId()).pageExecute(request);
    }

    private AlipayTradePrecreateResponse _qrPay(PaymentModel paymentModel) throws AlipayApiException {
        AlipayTradePrecreateRequest request = new AlipayTradePrecreateRequest();
        AlipayTradePrecreateModel payModel = new AlipayTradePrecreateModel();
        OrderModel orderModel = orderService.getById(paymentModel.getOrderId());
        payModel.setOutTradeNo(paymentModel.getOrderSn());
        payModel.setTotalAmount(paymentModel.getPaymentAmountDecimal().toPlainString());
        payModel.setSubject(orderService.getOrderOnlinePayTitle(paymentModel.getOrderId()));
        payModel.setTimeoutExpress(StrUtil.format("{}m", diamondConfig.getOrderPayValiditySeconds() / 60));
        request.setNotifyUrl(groupService.getById(orderModel.getGroupId()).getAlipayNotifyUrl());
        request.setBizModel(payModel);
        return getClient(orderModel.getGroupId()).execute(request);
    }

    private AlipayTradeCreateResponse _defaultPay(PaymentModel paymentModel) throws AlipayApiException {
        AlipayTradeCreateRequest request = new AlipayTradeCreateRequest();
        AlipayTradeCreateModel payModel = new AlipayTradeCreateModel();
        OrderModel orderModel = orderService.getById(paymentModel.getOrderId());
        payModel.setTimeoutExpress(StrUtil.format("{}m", diamondConfig.getOrderPayValiditySeconds() / 60));
        payModel.setOutTradeNo(paymentModel.getOrderSn());
        payModel.setTotalAmount(paymentModel.getPaymentAmountDecimal().toPlainString());
        payModel.setSubject(orderService.getOrderOnlinePayTitle(paymentModel.getOrderId()));
        request.setNotifyUrl(groupService.getById(orderModel.getGroupId()).getAlipayNotifyUrl());
        request.setBizModel(payModel);
        return getClient(orderModel.getGroupId()).execute(request);
    }


    protected AlipayClient getClient(Long groupId) {
        //log.info("支付签名，创建支付宝连接,平台id,{}",groupId);
        // 获取或创建该 groupId 的锁对象
        //Object lock = lockMap.computeIfAbsent(groupId, k -> new Object());
       // synchronized (lock) {
          //  if (alipayClient == null) {
                var group = groupService.getById(groupId);
                //log.info("创建支付宝连接,平台id,{},appId,{},{},{}", groupId, group.getAlipayAppId(),group.getAlipayAppPrivateKey(),group.getAlipayPublicKey());
                alipayClient = new DefaultAlipayClient(
                        alipayConfig.getGateway(),
                        group.getAlipayAppId(),
                        group.getAlipayAppPrivateKey(), "json",
                        alipayConfig.getCharset(),
                        group.getAlipayPublicKey(), "RSA2");

           // }
            return alipayClient;
      //  }
    }
}
